package com.ibangnuo.manage.service.wxpay;

import com.alibaba.fastjson.JSONObject;
import com.github.wxpay.sdk.WXPay;
import com.github.wxpay.sdk.WXPayConfig;
import com.github.wxpay.sdk.WXPayRequest;
import com.github.wxpay.sdk.WXPayUtil;
import com.ibangnuo.framework.domain.*;
import com.ibangnuo.framework.domain.request.wxpay.WxpayDomainRequest;
import com.ibangnuo.framework.domain.response.alipay.PayCode;
import com.ibangnuo.framework.model.response.CommonCode;
import com.ibangnuo.framework.model.response.ObjectResult;
import com.ibangnuo.framework.utils.PrimaryKeyUtil;
import com.ibangnuo.manage.dao.OrderDetailsRepository;
import com.ibangnuo.manage.dao.OrderRepository;
import com.ibangnuo.manage.dao.alipay.PayRepository;
import com.ibangnuo.manage.dao.employee.CommercialRepository;
import com.ibangnuo.manage.dao.terminal.TerminalRepository;
import com.ibangnuo.manage.service.wxpay.impl.WxpayConfigImpl;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.text.DecimalFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

/**
 * @Author: wwy
 * @Date: 2020-01-17 9:45
 */
@Service
public class WxpayService {
    private static Logger LOGGER = LoggerFactory.getLogger(WxpayService.class);
    @Value("${wx.query.pollingCount}")
    private int pollingCount;
    @Value("${wx.query.pollingMilliseconds}")
    private int pollingMilliseconds;
    @Value("${wx.spbill_create_ip}")
    private String spbillCreateIp;

    @Autowired
    private CommercialRepository commercialRepository;
    @Autowired
    private TerminalRepository terminalRepository;
    @Autowired
    private OrderRepository orderRepository;
    @Autowired
    private OrderDetailsRepository orderDetailsRepository;
    @Autowired
    private PayRepository payRepository;
    @Autowired
    private WXPayConfig wxPayConfig;

    /**
     * 微信支付流程
     * 1.根据sn号查询商家，获取商家id,查询商家获取mchid;为空，不进行支付
    *
     * @param wxpayDomainRequest
     * @return
     */
    public ObjectResult pay(WxpayDomainRequest wxpayDomainRequest) {
        if (wxpayDomainRequest == null) {
            return new ObjectResult(CommonCode.INVALID_PARAM, null);
        }
        if (StringUtils.isEmpty(wxpayDomainRequest.getAuthCode())) {
            return new ObjectResult(CommonCode.INVALID_PARAM, null);
        }
        Order order = new Order();
        order.setCreateTime(new Date());
        //根据机具id查询商家
        Terminal terminal = terminalRepository.findBySn(wxpayDomainRequest.getDeviceSn());
        CommercialTenant commercialTenant = this.getById(terminal.getCommercialTenantId());
        if(commercialTenant == null || StringUtils.isEmpty(commercialTenant.getMchId())){
            return new ObjectResult(CommonCode.FAIL,null);
        }
        wxpayDomainRequest.setMchId(commercialTenant.getMchId());
        if (terminal != null) {
            order.setShopId(terminal.getShopId());
        }

        if (StringUtils.isNotEmpty(wxpayDomainRequest.getMchId())) {
            CommercialTenant mchIdCommercialTenant = commercialRepository.findByMchId(wxpayDomainRequest.getMchId());
            order.setCommercialTenantId(mchIdCommercialTenant.getId());//所属商户
        }
        //order.setActualPayment(Integer.parseInt(new DecimalFormat("0").format(wxpayDomainRequest.getTotalFee() * 100)));
        order.setConsumeMoney(Integer.parseInt(new DecimalFormat("0").format(wxpayDomainRequest.getTotalFee() * 100)));
        order.setNote(wxpayDomainRequest.getWaterNote());//订单备注
        order.setStatus(0);//待支付
        order.setPayType(wxpayDomainRequest.getPayType());//支付类型
        order.setPayWay(1);
        order.setSn(wxpayDomainRequest.getDeviceSn());//机具sn


        Order save = orderRepository.save(order);
        Map<String, String> response = this.payResult(wxpayDomainRequest);
        OrderDetails orderDetails = new OrderDetails();
        orderDetails.setCreateTime(new Date());
        String responseStrJson = JSONObject.toJSONString(response);
        Pay pay = new Pay();
        if (response != null) {
            String returnCode = response.get("return_code");
            if ("SUCCESS".equals(returnCode)) {
                //业务结果
                String resultCode = response.get("result_code");
                if ("SUCCESS".equals(resultCode)) {
                    //支付成功
                    save.setStatus(1);
                    save.setActualPayment(Integer.parseInt(response.get("total_fee")));//订单金额
                    save.setSerialNumber(response.get("transaction_id"));//流水号
                    save.setOutTradeNo(response.get("out_trade_no"));//外部订单号
                    orderRepository.save(save);
                    orderDetails.setCreateTime(new Date());
                    orderDetails.setOrderId(save.getId());
                    orderDetails.setContent(responseStrJson);
                    orderDetailsRepository.save(orderDetails);
                    pay.setCreateTime(new Date());
                    pay.setDescribe("支付成功");
                    pay.setMoney(Integer.parseInt(response.get("total_fee")));
                    pay.setOrderId(save.getId());
                    pay.setStatus(1);
                    payRepository.save(pay);
                    return new ObjectResult(PayCode.PAY_SUCCESS, null);
                } else {
                    //用户正在输入支付密码
                    if ("USERPAYING".equals(response.get("err_code"))) {
                        //进行轮询
                        Map<String, Object> map = this.orderQueryResult(response.get("transaction_id"));
                        if(map!=null&&"00000".equals(map.get("returnCode"))){
                            //支付成功
                            Map<String, String> content = (Map<String,String>)map.get("content");
                            save.setStatus(1);
                            save.setActualPayment(Integer.parseInt(content.get("total_fee")));//订单金额
                            save.setSerialNumber(content.get("transaction_id"));//流水号
                            save.setOutTradeNo(content.get("out_trade_no"));//外部订单号
                            orderRepository.save(save);
                            orderDetails.setCreateTime(new Date());
                            orderDetails.setOrderId(save.getId());
                            orderDetails.setContent(responseStrJson);
                            orderDetailsRepository.save(orderDetails);
                            pay.setCreateTime(new Date());
                            pay.setDescribe("支付成功");
                            pay.setMoney(Integer.parseInt(content.get("total_fee")));
                            pay.setOrderId(save.getId());
                            pay.setStatus(1);
                            payRepository.save(pay);
                            return new ObjectResult(PayCode.PAY_FILL,null);
                        }
                    }
                }
            }
        }
        pay.setCreateTime(new Date());
        pay.setDescribe("支付失败");
        pay.setMoney(Integer.parseInt(new DecimalFormat("0").format(wxpayDomainRequest.getTotalFee() * 100)));
        pay.setOrderId(save.getId());
        pay.setStatus(1);
        payRepository.save(pay);
        save.setStatus(2);
        orderRepository.save(save);
        orderDetails.setOrderId(save.getId());
        orderDetails.setContent(responseStrJson);
        orderDetailsRepository.save(orderDetails);
        return new ObjectResult(PayCode.PAY_FILL,null);

    }

    /**
     * 具体支付接口调用
     *
     * @param wxpayDomainRequest
     * @return
     */
    public Map<String, String> payResult(WxpayDomainRequest wxpayDomainRequest) {
        String url = "/pay/micropay";

        try {
            WXPay wxPay = new WXPay(wxPayConfig);
            Map<String, String> reqData = new HashMap<>();
            reqData.put("body", wxpayDomainRequest.getBody());//商品介绍
            reqData.put("out_trade_no", PrimaryKeyUtil.nextId() + "");//订单号
            reqData.put("total_fee", new DecimalFormat("0").format(wxpayDomainRequest.getTotalFee() * 100));//订单总金额
            reqData.put("spbill_create_ip", spbillCreateIp);//终端ip
            reqData.put("auth_code", wxpayDomainRequest.getAuthCode());
            reqData.put("sub_mch_id",wxpayDomainRequest.getMchId());
            Map<String, String> requestMap = wxPay.fillRequestData(reqData);
            WXPayRequest wxPayRequest = new WXPayRequest(wxPayConfig);
            String data = WXPayUtil.mapToXml(requestMap);
            String response = wxPayRequest.requestWithoutCert(url, "", data, true);
            Map<String, String> responseMap = WXPayUtil.xmlToMap(response);
            return responseMap;
        } catch (Exception e) {
            LOGGER.error("微信支付异常:{}", e.getMessage());
        }
        return null;
    }

    /**
     * 支付其他操作
     * 1.用户需要输入密码
     * 2.轮询调用
     */
    public void otherPay() {

    }

    /**
     * 轮询调用订单查询
     *
     * @param outTradeNo
     * @return
     */
    private Map<String,Object> orderQueryResult(String outTradeNo){
        String url = "/sandboxnew/pay/orderquery";
        WXPayConfig wxPayConfig = new WxpayConfigImpl();
        Map<String,Object> returnMap = new HashMap<>();
        try {
            WXPay wxPay = new WXPay(wxPayConfig);
            Map<String, String> reqData = new HashMap<>();
            reqData.put("out_trade_no", outTradeNo);//订单号
            Map<String, String> requestMap = wxPay.fillRequestData(reqData);
            WXPayRequest wxPayRequest = new WXPayRequest(wxPayConfig);
            String data = WXPayUtil.mapToXml(requestMap);
            int count = 0;
            Map<String, String> responseMap = null;
            while (true) {
                if (count == pollingCount) {
                    //调用交易撤销接口
                    this.reverseResult(outTradeNo);
                }
                String response = wxPayRequest.requestWithoutCert(url, "", data, true);
                responseMap = WXPayUtil.xmlToMap(response);
                if (responseMap != null) {
                    if("SUCCESS".equals(responseMap.get("return_code"))&&"SUCCESS".equals(responseMap.get("result_code"))){
                        if("SUCCESS".equals(responseMap.get("trade_state"))){
                            //支付成功
                            returnMap.put("returnCode","00000");
                            returnMap.put("message","支付成功");
                            returnMap.put("content",responseMap);
                            break;
                        }
                        if("PAYERROR".equals(responseMap.get("trade_state"))){
                            //支付失败
                            returnMap.put("returnCode","55555");
                            requestMap.put("message","支付失败");
                            break;
                        }
                        if("USERPAYING".equals(responseMap.get("trade_state"))){
                            Thread.sleep(pollingMilliseconds);
                            count++;
                        }
                        if("CLOSED".equals(responseMap.get("trade_state"))){
                            //订单已关闭
                            returnMap.put("returnCode","55555");
                            requestMap.put("message","订单已关闭");
                            break;
                        }
                    }else{
                        returnMap = null;
                        break;
                    }
                } else {
                    requestMap = null;
                    break;
                }
            }


            return returnMap;
        } catch (Exception e) {
            LOGGER.error("微信支付异常:{}",e.getMessage());
        }
        return null;
    }

    /**
     * 撤销订单接口调用
     */
    private void reverseResult(String outTradeNo){
        String url = "/pay/micropay";
        WXPayConfig wxPayConfig = new WxpayConfigImpl();
        try {
            WXPay wxPay = new WXPay(wxPayConfig);
            Map<String, String> reqData = new HashMap<>();
            reqData.put("out_trade_no", outTradeNo);//订单号
            Map<String, String> requestMap = wxPay.fillRequestData(reqData);
            WXPayRequest wxPayRequest = new WXPayRequest(wxPayConfig);
            String data = WXPayUtil.mapToXml(requestMap);
            String response = wxPayRequest.requestWithCert(url, "", data, 1000,1000,true);
            Map<String, String> responseMap = WXPayUtil.xmlToMap(response);
            if(responseMap !=null){
                if("SUCCESS".equals(responseMap.get("return_code"))){
                LOGGER.info("订单已经撤销订单号:{}",outTradeNo);
                }
            }
        } catch (Exception e) {
            LOGGER.error("微信支付异常:{}",e.getMessage());
        }
    }

    /**
     * 仿真测试key获取
     *
     * @return
     */
    public ObjectResult payTestResult() {
        WXPayConfig wxPayConfig = new WxpayConfigImpl();
        try {
            WXPay wxPay = new WXPay(wxPayConfig);
            Map<String, String> reqData = new HashMap<>();
            Map<String, String> requestMap = wxPay.fillRequestData(reqData);
            WXPayRequest wxPayRequest = new WXPayRequest(wxPayConfig);
            String data = WXPayUtil.mapToXml(requestMap);
            String response = wxPayRequest.requestWithoutCert("/sandboxnew/pay/getsignkey", "", data, true);
            Map<String, String> responseMap = WXPayUtil.xmlToMap(response);
            return new ObjectResult(CommonCode.SUCCESS, responseMap);
        } catch (Exception e) {
            LOGGER.error("微信支付异常:{}", e.getMessage());
        }
        return new ObjectResult(CommonCode.FAIL, null);
    }

    /**
     * 退款查询
     *
     * @Param outTradeNo
     * @Retuen
     */
    public Map<String, String> RefundQuery(String outTradeNo, String subMchId) {
        String urlSuffix = "/pay/refundquery";
        WXPayConfig wxPayConfig = new WxpayConfigImpl();
        Map<String,String> returnMap=new HashMap<>();
        try {
            WXPay wxPay = new WXPay(wxPayConfig);
            //构建参数
            Map<String, String> dataMap = new HashMap<String, String>();
            //自行实现该随机串
            dataMap.put("sub_mch_id", subMchId);//子商户号
            dataMap.put("out_trade_no", outTradeNo);//商户订单号
            Map<String, String> requestMap = wxPay.fillRequestData(dataMap);
            Map<String, String> refund = wxPay.refundQuery(requestMap);//退款查询参数
            String toXml = WXPayUtil.mapToXml(refund);
            String uuid = String.valueOf(System.currentTimeMillis());
            WXPayRequest wxPayRequest = new WXPayRequest(wxPayConfig);
            String refundQuery = wxPayRequest.requestWithoutCert(urlSuffix, uuid, toXml, true);
            Map<String, String> responseMap = WXPayUtil.xmlToMap(refundQuery);
            String return_code = responseMap.get("return_code");
            if ("SUCCESS".equals(return_code)) {//申请退款成功
                returnMap.put("returnCode","55555");
                returnMap.put("message","退款申请成功");
                String result_status = responseMap.get("refund_status_$n");
                if ("SUCCESS".equals(result_status)) {//退款成功
                    returnMap.put("returnCode","00000");
                    returnMap.put("message","退款成功");
                } else if ("REFUNDCLOSE".equals(result_status)) {//退款关闭
                    returnMap.put("returnCode","11111");
                    returnMap.put("message","退款关闭");
                } else if ("PROCESSING".equals(result_status)) {//退款处理中
                    returnMap.put("returnCode","22222");
                    returnMap.put("message","退款处理中");
                } else if ("CHANGE".equals(result_status)) {//退款异常
                    returnMap.put("returnCode","33333");
                    returnMap.put("message","退款异常");
                }
            } else {//申请退款失败
                returnMap.put("returnCode","44444");
                returnMap.put("message","退申请款失败");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return returnMap;
    }

    /**
     * 授权码查询公众号opendId
     *
     * @Param
     * @Retuen
     */
    public Map<String, String> OpenId(String authCode, String subMchId) {
        String urlSuffix = "/tools/authcodetoopenid";
        WXPayConfig wxPayConfig = new WxpayConfigImpl();
        Map<String,String> returnMap=new HashMap<>();
        try {
            WXPay wxPay = new WXPay(wxPayConfig);
            //构建参数
            Map<String, String> dataMap = new HashMap<String, String>();
            dataMap.put("sub_mch_id", subMchId);//子商户号
            dataMap.put("auth_code", authCode);//授权码
            Map<String, String> requestMap = wxPay.fillRequestData(dataMap);
            Map<String, String> authCodeToOpenid = wxPay.authCodeToOpenid(requestMap);//授权码查询公众号opendId查询参数
            String toXml = WXPayUtil.mapToXml(authCodeToOpenid);
            String uuid = String.valueOf(System.currentTimeMillis());//唯一标识
            WXPayRequest wxPayRequest = new WXPayRequest(wxPayConfig);
            String refundQuery = wxPayRequest.requestWithoutCert(urlSuffix, uuid, toXml, true);//成功会返回的参数
            Map<String, String> stringStringMap = WXPayUtil.xmlToMap(refundQuery);
            String return_code = stringStringMap.get("return_code");//返回状态码
            if ("SUCCESS".equals(return_code)) {
                String resultCode = stringStringMap.get("result_code");
                if ("SUCCESS".equals(resultCode)) {//查询公众号opendId成功
                    String openid = stringStringMap.get("openid");

                }

            } else {//openId查询失败

            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     *交易保障
     *
     * @Param
     * @Retuen
     */
    public Map<String, String> Report(String interfaceUrl, String subMchId) {
        String urlSuffix = "/payitil/report";
        WXPayConfig wxPayConfig = new WxpayConfigImpl();
        try {
            WXPay wxPay = new WXPay(wxPayConfig);
            //构建参数
            Map<String, String> dataMap = new HashMap<String, String>();
            dataMap.put("sub_mch_id", subMchId);//子商户号
            dataMap.put("interface_url","https://api.mch.weixin.qq.com/pay/batchreport/micropay/total");
            dataMap.put("user_ip","");//当前的机器ip
            Map<String, String> requestMap = wxPay.fillRequestData(dataMap);
            Map<String, String> authCodeToOpenid = wxPay.report(requestMap);//支付保障的参数
            String toXml = WXPayUtil.mapToXml(authCodeToOpenid);
            String uuid = String.valueOf(System.currentTimeMillis());//唯一标识
            WXPayRequest wxPayRequest = new WXPayRequest(wxPayConfig);
            String refundQuery = wxPayRequest.requestWithoutCert(urlSuffix, uuid, toXml, true);//成功会返回的参数
            Map<String, String> stringStringMap = WXPayUtil.xmlToMap(refundQuery);
            String return_code = stringStringMap.get("return_code");//返回状态码
            //todo 调用订单查询的接口，其返回值的result_code是否为success来判断交易是否成功
            if ("SUCCESS".equals(return_code) ) {

                String resultCode = stringStringMap.get("result_code");
                if ("SUCCESS".equals(resultCode)) {//查询公众号opendId成功


                }

            } else {//openId查询失败

            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 根据商家id查询商家
     * @param id
     * @return
     */
    private CommercialTenant getById(String id){
        Optional<CommercialTenant> optional = commercialRepository.findById(id);
        if(optional.isPresent()){
            return optional.get();
        }
        return null;
    }


}
